﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UBlockly.Compotent;
using UBlockly.Scriptable;
using System;

namespace UBlockly.UI
{
    /// <summary>
    /// 参数对象
    /// </summary>
    [RequireComponent(typeof(UImage))]
    [RequireComponent(typeof(UParamComponentAnchor))]
    internal class ParamObject : MonoBehaviour
    {
        private RectPacker packer;
        public string paramTypeStr;
        private Node DefaultParamNode;
        public uint ParamIndex;
        public IParamGetterCompotent DefaultParamGetter => transform.GetChild(0).GetComponent<IParamGetterCompotent>();

        public void InitParam(Action bodyChangeNotify)
        {
            var paramType = TranslateHelper.GetILVarTypeByVarTypeName(paramTypeStr);
            packer = new RectPacker(GetComponent<UParamComponentAnchor>(), paramTypeStr);
            string defaultFuncName = $"Get{paramType}";
            DefaultParamIlFunc paramFunc = new DefaultParamIlFunc(defaultFuncName, DefaultParamGetter.GetterValue);
            NodeScriptable x = new NodeScriptable(paramFunc,paramTypeStr);
            DefaultParamNode = new EmptyBlockNode(x,DefaultParamGetter);
            DefaultParamNode.BodyChangeNotify = bodyChangeNotify;
        }

        public Node GetCurrentParam()
        {
            var lst = transform.childCount;
            return lst == 1 ? DefaultParamNode : transform.GetChild(lst - 1).GetComponent<BlockObject>().Node.Value;
        }

        public void ActiveDefaultParam()
        {
            packer.BlockAnchor.transform.GetChild(0).gameObject.SetActive(true);
        }

        public bool IsPacked()
        {
            return packer.BlockAnchor.transform.childCount == 2;
        }

        public void PackNode(Node node)
        {
            node.Block.AttacthToBlock(packer.BlockAnchor);//设置物理挂载关系
            packer.BlockAnchor.transform.GetChild(0).gameObject.SetActive(false);
            if (packer.BlockAnchor.transform.childCount == 1)
            {
                DefaultParamNode.Block.gameObject.SetActive(true);
            }
            
        }

        public IRectPacker GetPacker()
        {
            return packer;
        }
    }

    [RequireComponent(typeof(UPackerAnchor))]
    internal class PackerObject : MonoBehaviour
    {
        private Node belongNode;
        [SerializeField]
        private List<ParamObject> paramList = new List<ParamObject>();
        public int PackerCount => paramList.Count;

        public void BindParamObject(int index, string paramTypeStr,ParamObject paramObject)
        {
            paramObject.ParamIndex = (uint)index;
            paramObject.paramTypeStr = paramTypeStr;
            paramList.Add(paramObject);
        }

        public ParamObject GetParamObject(int index)
        {
            return paramList[index];
        }

        public void DoInit(Node node)
        {
            belongNode = node;
            foreach (var param in paramList)
            {
                param.InitParam(node.BodyChangeNotify);
                param.DefaultParamGetter.ParamSelectHandler = node.Block.EventHandler.OnBlockParamSelect;
                param.DefaultParamGetter.ParamDeselectHandler = node.Block.EventHandler.OnBlockParamDeselect;
            }
        }

        public ParamObject FindParamPacker(System.Predicate<long> predicate)
        {
            for (int i = 0; i < paramList.Count; i++)
            {
                if (paramList[i].GetCurrentParam() == null)
                    Debug.LogError("222");
                if (predicate(paramList[i].GetCurrentParam().Id))
                    return paramList[i];
            }
            return null;
        }

        public void PackNode(Node node, int index)
        {
            paramList[index].PackNode(node);
            node.BodyChangeNotify = belongNode.ResizeNode;
            //node.Block.EventHandler.
            belongNode.ResizeNode();
        }

        public Node UnPackNode(int index)
        {
            Node targetNode = null;
            if (paramList[index].IsPacked())
            {
                targetNode = GetParamObject(index).GetCurrentParam();
                paramList[index].ActiveDefaultParam();
                targetNode.Block.transform.SetParent(null);
            }
            belongNode.ResizeNode();
            return targetNode;
        }

        public List<ParamObject> GetParamObjects()
        {
            return paramList;
        }
    }
}
